package airacrobats.gear;

import airacrobats.gui.container.LoadingResourcesContainer;
import airacrobats.io.ImageLoader;
import airacrobats.io.Loader;
import airacrobats.io.LoaderListener;
import airacrobats.game.Squadron;
import airacrobats.io.FlapsLoader;
import airacrobats.io.ScoreLoader;
import airacrobats.io.SoundLoader;
import airacrobats.io.SquadronLoader;
import airacrobats.io.StageLoader;
import airacrobats.io.WavefrontLoader;
import airacrobats.io.data.FlapsData;
import java.awt.GridBagConstraints;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import javax.swing.SwingUtilities;

/**
 * This is the gear where the resources of the game are loaded.
 */
public class SplashGear extends Gear implements LoaderListener
{
    /**
     * Loading resources container.
     */
    private LoadingResourcesContainer loadingResourcesContainer;
    /**
     * Gear to go when the loading is complete.
     */
    private Gear gear;
    /**
     * The selected squadron.
     */
    private Squadron selectedSquadron;

    /**
     * @param gearListener The gear listener.
     */
    public SplashGear(GearListener gearListener, Gear gear, Squadron selectedSquadron)
    {
        super(gearListener);
        this.gear = gear;
        this.selectedSquadron = selectedSquadron;
    }

    /**
     */
    public void load()
    {
        loadingResourcesContainer = new LoadingResourcesContainer();

        GridBagConstraints c = new GridBagConstraints();

        c.gridx = 0;
        c.gridy = 0;
        add(loadingResourcesContainer, c);

        // If the selected squadron is null, it is loading the initial resources.
        if (selectedSquadron == null)
            loadInitialResources();
        else
            loadResources();
    }

    /**
     */
    public synchronized void loadFinished(Exception ex, Loader loader, double increment, String message)
    {
        if (ex != null)
        {
            Thread.getDefaultUncaughtExceptionHandler().uncaughtException(null, ex);
        }

        if (loader == stageLoader)
        {
            // Loads the stages images.
            Map<String, String> files = new HashMap<String, String>();
            for (int i = 0; i < stageLoader.getCount(); ++i)
            {
                files.put(selectedSquadron.getType().getMapKey() + "/Stage" + i + ".jpg",
                    selectedSquadron.getType().getPackageName() + "/image/Stage" + i + ".jpg");
            }
            imageLoader.startLoading(files, this, 0.1, "Images loaded", false);
        }
        else if (loader == flapsLoader)
        {
            wavefrontLoader = new WavefrontLoader();
            Map<String, String> map = new HashMap<String, String>();
            map.put(selectedSquadron.getType().getMapKey() + "/Airplane.obj",
                    selectedSquadron.getType().getPackageName() + "/model/Airplane.obj");
            map.put(selectedSquadron.getType().getMapKey() + "/AirplaneShadow.obj",
                    selectedSquadron.getType().getPackageName() + "/model/AirplaneShadow.obj");
            map.put(selectedSquadron.getType().getMapKey() + "/Smoke.obj",
                    selectedSquadron.getType().getPackageName() + "/model/Smoke.obj");
            map.put(selectedSquadron.getType().getMapKey() + "/Terrain.obj",
                    selectedSquadron.getType().getPackageName() + "/model/Terrain.obj");
            map.put(selectedSquadron.getType().getMapKey() + "/Sky.obj",
                    selectedSquadron.getType().getPackageName() + "/model/Sky.obj");
            map.put(selectedSquadron.getType().getMapKey() + "/Propeller.obj",
                    selectedSquadron.getType().getPackageName() + "/model/Propeller.obj");
            
            for (FlapsData flapsData : flapsLoader.getObjects())
            {
                map.put(selectedSquadron.getType().getMapKey() + "/" + flapsData.getModelName() + ".obj",
                        selectedSquadron.getType().getPackageName() + "/model/" + flapsData.getModelName() + ".obj");
            }
            wavefrontLoader.startLoading(map, this, 0.4, "Models loaded", false);
        }

        try
        {
            updateProgressBar(increment, message);
            if (loadingResourcesContainer.isProgressBarFull())
            {
                SwingUtilities.invokeAndWait(new Runnable()
                {
                    public void run()
                    {
                        gear.load();
                        gearListener.gearChanging(gear);
                    }
                }); 
            }
        }
        catch (InterruptedException exc)
        {
            Thread.getDefaultUncaughtExceptionHandler().uncaughtException(null, exc);
        }
        catch (InvocationTargetException exc)
        {
            Thread.getDefaultUncaughtExceptionHandler().uncaughtException(null, exc);
        }
    }

    /**
     * Loads the initial resources.
     */
    private void loadInitialResources()
    {
        imageLoader = new ImageLoader();
        squadronLoader = new SquadronLoader();

        Map<String, String> imageFiles = new HashMap<String, String>();
        Map<String, String> dataFiles = new HashMap<String, String>();
        for (Squadron.Type squadron : Squadron.Type.values())
        {
            imageFiles.put(squadron.getMapKey() + "/Preview.png",
                    squadron.getPackageName() + "/image/Preview.png");
            dataFiles.put(squadron.getMapKey() + "/Squadron.dat",
                    squadron.getPackageName() + "/dat/Squadron.dat");
        }

        imageLoader.startLoading(imageFiles, this, 0.8, "Images loaded", false);
        squadronLoader.startLoading(dataFiles, this, 0.2, "Scores loaded", false);

        loadingResourcesContainer.updateProgress(0, "Loading initial resources");
    }

    /**
     * Loads the resources.
     */
    private void loadResources()
    {
        stageLoader = new StageLoader();
        Map<String, String> map = new HashMap<String, String>();
        map.put(selectedSquadron.getType().getMapKey() + "/Stages.dat",
                selectedSquadron.getType().getPackageName() + "/dat/Stages.dat");
        stageLoader.startLoading(map, this, 0.1, "Stages loaded", true);

        scoreLoader = new ScoreLoader();
        map = new HashMap<String, String>();
        map.put(selectedSquadron.getType().getMapKey() + "/Scores.dat",
                selectedSquadron.getType().getPackageName() + "/dat/Scores.dat");
        scoreLoader.startLoading(map, this, 0.1, "Scores loaded", true);

        soundLoader = new SoundLoader();
        map = new HashMap<String, String>();
        map.put(selectedSquadron.getType().getMapKey() + "/Engine0.ogg",
                selectedSquadron.getType().getPackageName() + "/sound/Engine0.ogg");
        map.put(selectedSquadron.getType().getMapKey() + "/Engine1.ogg",
                selectedSquadron.getType().getPackageName() + "/sound/Engine1.ogg");
        map.put(selectedSquadron.getType().getMapKey() + "/Engine2.ogg",
                selectedSquadron.getType().getPackageName() + "/sound/Engine2.ogg");
        map.put(selectedSquadron.getType().getMapKey() + "/Engine3.ogg",
                selectedSquadron.getType().getPackageName() + "/sound/Engine3.ogg");
        map.put(selectedSquadron.getType().getMapKey() + "/Wind.ogg",
                selectedSquadron.getType().getPackageName() + "/sound/Wind.ogg");

        for (int i = 0; i < selectedSquadron.getSquadronData().getRadioSounds(); ++i)
        {
            map.put(selectedSquadron.getType().getMapKey() + "/Radio" + i + ".ogg",
                selectedSquadron.getType().getPackageName() + "/sound/Radio" + i + ".ogg");
        }

        map.put(selectedSquadron.getType().getMapKey() + "/Replay.ogg",
                selectedSquadron.getType().getPackageName() + "/sound/Replay.ogg");
        soundLoader.startLoading(map, this, 0.2, "Sounds loaded", false);

        flapsLoader = new FlapsLoader();
        map = new HashMap<String, String>();
        map.put(selectedSquadron.getType().getMapKey() + "/Flaps.txt",
                selectedSquadron.getType().getPackageName() + "/dat/Flaps.txt");
        flapsLoader.startLoading(map, this, 0.1, "Flaps data loaded", true);
    
        loadingResourcesContainer.updateProgress(0, "Loading resources");
    }

    /**
     * Updates the progress bar.
     * @param increment The increment value.
     * @param message The message.
     * @throws InterruptedException Thrown if an exception is thrown on the run execution.
     * @throws InvocationTargetException Thrown if the run thread is interrupted.
     */
    private void updateProgressBar(final double increment, final String message) throws InterruptedException, InvocationTargetException
    {
        SwingUtilities.invokeAndWait(new Runnable()
        {
            public void run()
            {
                loadingResourcesContainer.updateProgress(increment, message);
            }
        });
    }
}
